import json
import tkinter as tk
from tkinter import messagebox, ttk

import requests

from config import Env, env
from utils.json_encryptor import decrypt_json
from utils.utils import CommonUtils


class Dialog:

    def __init__(self, master, title="", size=None):
        """
        对话框基础类，实现位置以及大小
        :param master:
        :param title:
        :param size: 占主窗口 1/size 尺寸
        """
        self.master = master

        self.dialog = tk.Toplevel(master)
        self.dialog.resizable(False, False)
        self.dialog.title(title)
        self.dialog.iconphoto(False, tk.PhotoImage(file=CommonUtils.resource_path(["resource", "icon_cleaned.png"])))
        self._position(size=size)

    def _find_root_tk(self):
        root, current = None, None
        while True:
            current = getattr(self if current is None else current, "master", None)
            try:
                title = current.title()
            except AttributeError:
                root = current
                continue

            if current and title == 'Little Empire':
                root = current
                break
        return root

    def _position(self, size=None):
        # ✅ 居中 + 主窗口 1/3 尺寸
        self.master.update_idletasks()
        root = self._find_root_tk()
        master_x = root.winfo_rootx()
        master_y = root.winfo_rooty()
        master_w = root.winfo_width()
        master_h = root.winfo_height()

        if size == 3:
            win_w = min(int(master_w / 3), master_w)
            win_h = min(int(master_h * 2 / 3), master_h)
        elif size is None:
            win_w = 300
            win_h = 150
        else:
            win_w = master_w
            win_h = master_h
        pos_x = master_x + (master_w - win_w) // 2
        pos_y = master_y + (master_h - win_h) // 2
        self.dialog.geometry(f"{win_w}x{win_h}+{pos_x}+{pos_y}")
        self.dialog.grab_set()


class MultiInputDialog(Dialog):
    def __init__(self, master, fields, title="请输入参数"):
        """
        通用多输入框对话框
        :param master: 父窗口
        :param fields: 要求输入的字段名列表，例如 ['长度', '宽度', '高度']
        :param title: 对话框标题
        """
        super().__init__(master, title=title, size=3)
        self.entries = {}
        self.result = None
        self.fields = fields

        # 外层 frame + canvas + scrollbar
        outer = tk.Frame(self.dialog)
        outer.pack(expand=True, fill="both")

        canvas = tk.Canvas(outer, highlightthickness=0)
        scrollbar = tk.Scrollbar(outer, orient="vertical", command=canvas.yview)
        scrollable_frame = tk.Frame(canvas)

        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )

        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

        # 动态生成输入框
        for k, field in fields.items():
            frame = tk.Frame(scrollable_frame)
            frame.pack(padx=10, pady=5, fill='x')
            tk.Label(frame, text=field + "：", width=8, anchor='w').pack(side='left')
            entry = tk.Entry(frame)
            entry.pack(side='right', expand=True, fill='x')
            self.entries[k] = entry

        # ✅ 单独的底部 Frame，固定在底部
        btn_frame = tk.Frame(self.dialog, height=2)
        btn_frame.pack(fill="x", padx=10, pady=10)

        confirm_btn = tk.Button(btn_frame, text="确认", command=self.on_confirm)
        confirm_btn.pack(fill="x")
        self.dialog.bind('<Return>', self.on_confirm)

        master.wait_window(self.dialog)

    def on_confirm(self, *args):
        values = {}
        try:
            for field, entry in self.entries.items():
                val = entry.get()
                if not val.strip():
                    raise ValueError(f"{self.fields[field]} 不能为空")
                try:
                    values[field] = float(val)
                except:
                    values[field] = val
            self.result = values
            self.dialog.destroy()
        except ValueError as e:
            messagebox.showerror("输入错误", str(e))

    def get_result(self):
        return self.result


class LoginDialog(Dialog):
    def __init__(self, master, title="口令"):
        super().__init__(master, title)
        self.invite_code_entry = None
        self.result = False
        if env == Env.debug:
            self.white_list = decrypt_json(CommonUtils.resource_path(["white_list.json.enc"]), password=CommonUtils.password)
        elif env == Env.prod:
            self.white_list = json.loads(requests.get("http://124.71.106.203/list").text)["list"]

        frame1 = tk.Frame(self.dialog)
        frame1.pack(fill=tk.X, expand=True)
        tk.Label(frame1, text='天王盖地虎', width=10).pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(30, 30), pady=5)
        frame = tk.Frame(self.dialog)
        frame.pack(fill=tk.X, expand=True)
        self.invite_code_entry = tk.Entry(frame)
        self.invite_code_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(30, 30), pady=5)

        # ✅ 单独的底部 Frame，固定在底部
        btn_frame = tk.Frame(self.dialog, height=2)
        btn_frame.pack(fill="x", padx=10, pady=10)

        confirm_btn = tk.Button(btn_frame, text="确认", command=self.on_confirm)
        confirm_btn.pack(fill="x")
        self.dialog.bind('<Return>', self.on_confirm)

        self.dialog.protocol("WM_DELETE_WINDOW", self.close)
        master.wait_window(self.dialog)

    def on_confirm(self, *args):
        invite_code = self.invite_code_entry.get()
        if invite_code in self.white_list:
        # if invite_code:
            self.result = True
            self.dialog.destroy()
        else:
            messagebox.showerror('', 'Invalid Code')

    def close(self):
        self.dialog.destroy()

    def get_result(self):
        return self.result

    def get_invite_code(self):
        return self.invite_code_entry.get()


class StylishRadioGroup(tk.Frame):
    def __init__(self, master, title="请选择一个选项：", options=None, default=None, command=None, **kwargs):
        super().__init__(master, bg="#f0f0f0", **kwargs)

        if options is None:
            options = {"补": 1, "不补": 0}
        if default is None:
            default = list(options.values())[0]

        self.command = command
        self.selected = tk.StringVar(value=default)

        # 标题
        self.title_label = ttk.Label(self, text=title)
        self.title_label.grid(row=0, column=0, sticky="nsew")

        # 单选框选项
        col = 1
        for name, value in options.items():
            rb = ttk.Radiobutton(self,
                                 text=name,
                                 variable=self.selected,
                                 value=value,
                                 command=self._on_select)
            col += 1
            rb.grid(row=0, column=col, sticky="nsew")

    def _on_select(self):
        if self.command:
            self.command(self.selected.get())

    def get(self):
        return self.selected.get()

    def set(self, value):
        self.selected.set(value)


class ScrollableFrame(ttk.Frame):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, borderwidth=2, relief="solid", **kwargs)

        self.canvas = tk.Canvas(self)
        self.scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        self.inner_frame = ttk.Frame(self.canvas)

        self.inner_frame.grid_columnconfigure(0, weight=1)

        # 把 inner_frame 放进 canvas
        self.canvas_window = self.canvas.create_window((0, 0), window=self.inner_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=self.scrollbar.set)

        self.canvas.grid(row=0, column=0, sticky="nsew")
        self.scrollbar.grid(row=0, column=1, sticky="ns")
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        # 关键点①：更新滚动区域
        self.inner_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        )

        # 关键点②：让 inner_frame 宽度跟 canvas 一样
        self.canvas.bind(
            "<Configure>",
            lambda e: self.canvas.itemconfig(self.canvas_window, width=e.width)
        )

        # 鼠标滚轮
        self.inner_frame.bind_all("<MouseWheel>", self._on_mousewheel)

    def _on_mousewheel(self, event):
        self.canvas.yview_scroll(-1 * (event.delta // 120), "units")